/*  tBookShelf: TextPlugin
    (C) 2007  TvN (Volodymyr Tarasenko), e-mail: tvntsr@yahoo.com

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/


#ifndef RENDER_AREA_PLUGINS_HPP
#define RENDER_AREA_PLUGINS_HPP

#include <iostream>

/// defines points
struct Point
{
    size_t X;
    size_t Y;

    Point(size_t x = 0, size_t y = 0)
        : X(x), Y(y)
    {}

    void swap()
    {
        size_t p = Y;
        Y = X;
        X = p;
    }
    void swap(Point& i)
    {
        Point a(*this);
        *this = i;
        i = a;
    }
};


/// defines rectangle
struct Rect
{
    Point start; // !< left bottom point
    Point end;   // !< right top point
};

inline
std::ostream& operator<<(std::ostream &o, const Point& p)
{
    o << "(" << p.X << "," << p.Y << ")";

    return o;
}

inline 
std::ostream& operator<<(std::ostream &o, const Rect& p)
{
    o << "(" << p.start << "x"<< p.end << ")";

    return o;
}


// Page orientation
enum PageOrientation
{
    Portrait,
    Landscape
    // :TODO: MirroredPortrait, MirroredLandscape
};


/// defines drawing area
struct DrawingArea
{
    Rect   coord;
    Point  pen;

    unsigned char*  buffer;
    size_t          width;

    DrawingArea()
        : coord(), pen(), buffer(0), width(0)
    {    }

    ~DrawingArea()
    {
        if (buffer)
            delete[] buffer;
    }

    inline 
    void setOverallDimension(const size_t& end_x,       
                             const size_t& end_y,
                             const size_t& start_x = 0, 
                             const size_t& start_y = 0)
    {
        coord.end.X = end_x;
        coord.end.Y = end_y;
        coord.start.X = start_x;
        coord.start.Y = start_y;
    }

    inline
    void putPenToStart()
    {
        pen.X = pen.Y = 0; 
    }
    inline 
    void movePen(const int& x, const int& y)
    {
        pen.X += x;
        pen.Y += y;
    }
    inline
    bool isMoveValid(const int& x, const int& y) const
    {
        return ((pen.Y+y < coord.end.Y)&&(pen.X+x < coord.end.X));
    }

    inline
    bool isPenValid() const
    {
        return ((pen.Y < coord.end.Y)&&(pen.X < coord.end.X));
    }
    inline
    bool isYPenValid() const
    {
        return (pen.Y < coord.end.Y);
    }
    inline
    bool isXPenValid() const
    {
        return (pen.Y < coord.end.Y);
    }

    inline
    unsigned char* createBuffer(bool fake = false);
   
    inline
    unsigned char* releaseBuffer();    

    inline void swap()
    {
        coord.start.swap();
        coord.end.swap();

        pen.swap();

//        width = (2*(coord.end.X - coord.start.X)+7)>>3;
    }

    inline 
    unsigned char* cloneBuffer()
    {
        unsigned char* cloned = 0;
        if (buffer)
        {
            size_t buffer_size = width * (coord.end.Y - coord.start.Y);
            cloned = new unsigned char[buffer_size];

            memcpy(cloned, buffer, buffer_size);
        }

        return cloned;
    }
    
private:
    // disable copying
    DrawingArea(const DrawingArea&);
    DrawingArea& operator=(const DrawingArea&);
};


inline
unsigned char* DrawingArea::createBuffer(bool fake)
{
    if (buffer)
    {
        delete[] buffer;

        buffer = 0;
    }

    width = (2 * (coord.end.X - coord.start.X) + 7) >> 3;

    size_t buffer_size = width * (coord.end.Y - coord.start.Y);

    std::cerr << "Create buff (width, height) :" 
              << width << "x" << (coord.end.Y - coord.start.Y)
              << std::endl;

    if (!fake)
    {
        buffer = new unsigned char[buffer_size];

        memset(buffer, 0xFF, buffer_size);
    }

    return buffer;
}

inline
unsigned char* DrawingArea::releaseBuffer()
{
    unsigned char* pbuf = buffer;

    buffer = 0;
    
    return pbuf;
}

#endif //RENDER_AREA_PLUGINS_HPP
